using System;
using System.Runtime.Serialization.Json;
using System.Text;
using System.IO;

namespace Ro.Norc.ServiceStackClient
{
	/// <summary>
	/// The standard JSON encoder
	/// </summary>
	public class ServiceEncoderJson : ServiceEncoderBase
	{			
		/// <summary>
		/// Creates a new ServiceEncodeJson instance
		/// </summary>
		public ServiceEncoderJson() : this("json")
		{
			return;
		}
		
		/// <summary>
		/// Creates a new ServiceEncodeJson instance
		/// </summary>
		/// <param name='endpointPart'>
		/// The string that is automatically appended to the URL by the Service class, should this behaviour be enabled
		/// </param>
		public ServiceEncoderJson(string endpointPart) : base()
		{
			if (string.IsNullOrEmpty(endpointPart)) {
				endpointPart = "json";
			}
			_allowedTypes = new string [] {
				"application/json",
				"application/json; charset=utf-8",
				"application/x-javascript",
				"text/javascript",
				"text/x-javascript",
				"text/x-json",
				"text/json"
			};
			_contentType = "application/json; charset=utf-8";
			_endpointPart = endpointPart;
		}
		
		/// <summary>
		/// Encodes a given object to a JSON string representation
		/// </summary>
		/// <param name="obj">
		/// The object to encode
		/// </param>
		/// <returns>
		/// The resulting JSON string representation or null if the given reference is null
		/// </returns>
		public override string Encode(object obj)
		{
			if (obj == null) {
				return null;
			}
			Type _type = obj.GetType();
			string _repr = null;
			
			try
			{
				MemoryStream _ms = new MemoryStream();
				DataContractJsonSerializer _serializer = new DataContractJsonSerializer(_type);
				StreamReader _msr = null;
				
				_serializer.WriteObject(_ms, obj);
				_ms.Position = 0;
				_msr = new StreamReader(_ms);
				_repr = _msr.ReadToEnd();
				_msr.Close();
				_ms.Close();
			}
			catch (Exception)
			{
				_repr = null;
			}
			
			return _repr;
		}
		
		/// <summary>
		/// Decodes a given JSON string representation to an object of the given type parameter T
		/// </summary>
		/// <param name="repr">
		/// The JSON string representation of the object that should be decoded
		/// </param>
		/// <param name="t">
		/// The type to be deserialized to
		/// </param>
		/// <returns>
		/// The resulting deserialized object
		/// </returns>
		public override object Decode(string repr, Type t)
		{
			if (string.IsNullOrEmpty(repr)) {
				return null;
			}
			object _obj = null;
			MemoryStream _ms = null;
			
			try
			{
				byte[] _bytes = Encoding.UTF8.GetBytes(repr);
				DataContractJsonSerializer _serializer = new DataContractJsonSerializer(t);
				_ms = new MemoryStream();
				_ms.Write(_bytes, 0, _bytes.Length);
				_ms.Position = 0;
				_obj = _serializer.ReadObject(_ms);
			}
			catch (Exception)
			{
				_obj = null;
			}
			finally
			{
				if (_ms != null) {
					_ms.Close();
				}
			}
			
			return _obj;
		}
	}
}